/*  _________________________________________
   /                                      /_ \
  |  			User Input               |/ \ |
  |                                      |___||
   \______________________________________\_/ |
       |                                      |
      /     User Input Receiver              /
     /     Written April, 2009,             /
    |     by Darrell Eastman.              |___
    |                                      |   |
     \______________________________________\_/
*/

/*
To receive events like mouse and keyboard input, or GUI events like "the OK
button has been clicked", we need an object which is derived from the
IEventReceiver object. There is only one method to override:
IEventReceiver::OnEvent(). This method will be called by the engine once
when an event happens. What we really want to know is whether a key is being
held down, and so we will remember the current state of each key.
*/

#include <iostream>
#include <irrlicht.h>
//#include "usermovement.h"

using namespace irr;
using namespace core;

//Action Key Map
struct KeyMap
{
	//Up
	SKeyMap			KeyUp;
	KeyUp.Action		= EKA_KEY_UP;
	KeyUp.KeyCode		= null;
	//Down
	SKeyMap			KeyDown;
	KeyDown.Action		= EKA_KEY_DOWN;
	KeyDown.KeyCode	= null;
	//Left
	SKeyMap			KeyLeft;
	KeyLeft.Action		= EKA_KEY_LEFT;
	KeyLeft.KeyCode	= null;
	//Right
	SKeyMap			KeyRight;
	KeyRight.Action	= EKA_KEY_RIGHT;
	KeyRight.KeyCode	= null;
	//Sprint
	SKeyMap			KeySprint;
	KeySprint.Action	= EKA_KEY_SPRINT;
	KeySprint.KeyCode	= null;
	//Jump
	SKeyMap			KeyJump;
	KeyJump.Action		= EKA_KEY_JUMP;
	KeyJump.KeyCode	= null;
	//Crouch
	SKeyMap			KeyCrouch;
	KeyCrouch.Action	= EKA_KEY_CROUCH;
	KeyCrouch.KeyCode	= null;
	//Action Pri
	SKeyMap			KeyActPri;
	KeyActPri.Action	= EKA_KEY_ACTPRI;
	KeyActPri.KeyCode	= null;
	//Action Sec
	SKeyMap			KeyActSec;
	KeyActSec.Action	= EKA_KEY_ACTSEC;
	KeyActSec.KeyCode	= null;
	//Use
	SKeyMap			KeyUse;
	KeyUse.Action		= EKA_KEY_USE;
	KeyUse.KeyCode		= null;
}

class GamePad : public IEventReciver
{
public:
	OnEvent()
}
const int SER_MOUSE_LEFT = 0;

const int SER_MOUSE_RIGHT = 1;

const int SER_MOUSE_MIDDLE = 2;

/*class SmoothEventReceiver : public IEventReceiver
{
public:
	int		m_key_cnt[256];
	int		m_key_buf[256];
	int		m_key_buf_old[256];
	int		m_key_up_down[256];
	int		m_key_down_up[256];
	int		m_key_shift[256];
	int		m_key_ctrl[256];
	int		m_key_menu[256];
	
	int		m_mouse_button_cnt[3];
	int		m_mouse_button_buf[3];
	int		m_mouse_button_buf_old[3];
	int		m_mouse_button_up_down[3];
	int		m_mouse_button_down_up[3];
	int		m_mouse_button_shift[3];
	int		m_mouse_button_ctrl[3];
	int		m_mouse_button_menu[3];

	int		m_mouse_x;
	int		m_mouse_y;
	float	m_mouse_z;

	createReceiver:SmoothEventReceiver()
	{
		return SmoothEventReceiver(SmoothEventReceiver.create(SmoothEventReceiver.generate));
	}

	int	OnEvent(SEvent event)
	{
		
		int event_type = event.getEventType();
		
		if( event_type = EET_KEY_INPUT_EVENT )
		{
			int key = event.getKeyInputKey();
		
			m_key_buf_old[key] = m_key_buf[key];
			m_key_buf[key] = event.getKeyPressedDown();

			//store the modifier flags
			m_key_shift[key] = event.getKeyShift();
			m_key_ctrl[key] = event.getKeyControl();
			m_key_menu[key] = IsKeyDown(EKEY_MENU) || IsKeyDown(EKEY_LMENU) || IsKeyDown(EKEY_RMENU);
			
			//store state changes
			m_key_up_down[key] = (m_key_buf[key] && ! m_key_buf_old[key]);
			m_key_down_up[key] = (! m_key_buf[key] && m_key_buf_old[key]);

			//log a key hit if the key is down and it wasnt down before
			if( m_key_up_down[key] ) m_key_cnt[key]:+1;
		}
		else if( event_type = EET_MOUSE_INPUT_EVENT )
		{
			int eventType = event.getMouseEventType();

			if( eventType < EMIE_MOUSE_MOVED )
			{
				int button = (event.getMouseEventType() Mod 3);
				
				//store the old state
				m_mouse_button_buf_old[button] = m_mouse_button_buf[button];
				
				//set the current state
				m_mouse_button_buf[button] = ! (event.getMouseEventType()/3);

				//store state changes
				m_mouse_button_up_down[button] = (m_mouse_button_buf[button] && ! m_mouse_button_buf_old[button]);
				m_mouse_button_down_up[button] = (! m_mouse_button_buf[button] && m_mouse_button_buf_old[button]);
				
				//log a hit if the state went from up to down
				if( m_mouse_button_up_down[button] ) m_mouse_button_cnt[button]:+1;
				
				//store the modifier flags
				m_mouse_button_shift[button] = IsKeyDown(EKEY_SHIFT) || IsKeyDown(EKEY_LSHIFT) || IsKeyDown(EKEY_RSHIFT);
				m_mouse_button_ctrl[button] = IsKeyDown(EKEY_CONTROL) || IsKeyDown(EKEY_LCONTROL) || IsKeyDown(EKEY_RCONTROL);
				m_mouse_button_menu[button] = IsKeyDown(EKEY_MENU) || IsKeyDown(EKEY_LMENU) || IsKeyDown(EKEY_RMENU);
			}
			else if( eventType = EMIE_MOUSE_MOVED )
			{
				m_mouse_x = event.getMouseX();
				m_mouse_y = event.getMouseY();
			}
			else if( eventType = EMIE_MOUSE_WHEEL )
			{
				m_mouse_z = event.getMouseWheel();
			}
		}
		
		return Super.OnEvent(event);
	}

	generate:IEventReceiver()
	{
		return new SmoothEventReceiver;
	}

	// ------------------------------------------------
	// keyboard functions
	// ------------------------------------------------
		

	int KeyHitCnt(int index, int bClear = false)
	{
		int retval = m_key_cnt[index];
		if( bClear ) m_key_cnt[index] = 0;
		return retval;
	}
	
	int IsKeyDown(int index, int bCheckShift = false, int bCheckCtrl = false, int bCheckMenu = false) 
	{
		// check the key itself
		int bKeyDown = m_key_buf[index];
		// check the shift modifier
		bKeyDown = bKeyDown && (! bCheckShift || m_key_shift[index]);
		// check the control modifier
		bKeyDown = bKeyDown && (! bCheckCtrl || m_key_ctrl[index]);
		// check the menu  modifier
		bKeyDown = bKeyDown && (! bCheckMenu || m_key_menu[index]);
		
		return bKeyDown;
	}
	
	int IsKeyUpDown(int index, int bClear = true)
	{
		int bIsKeyUpDown = m_key_up_down[index];
		if( bClear ) m_key_up_down[index] = false;
		return bIsKeyUpDown;
	}
	
	int IsKeyDownUp(int index, int bClear = true)
	{
		int bIsKeyDownUp = m_key_down_up[index];
		if( bClear ) m_key_down_up[index] = false;
		return bIsKeyDownUp;
	}

	FlushKeys()
	{
		m_key_cnt = new int[256];
		m_key_buf = new int[256];
		m_key_buf_old = new int[256];
		m_key_up_down = new int[256];
		m_key_down_up = new int[256];
		m_key_shift = new int[256];
		m_key_ctrl = new int[256];
		m_key_menu = new int[256];
	}

	//------------------------------------------------
	//mouse functions
	//------------------------------------------------

	int MouseHitCnt(int index, int bClear = false)
	{
		int retval = m_mouse_button_cnt[index];
		if( bClear ) m_mouse_button_cnt[index] = 0;
		return retval;
	}
	
	int IsMouseButtonDown(int index, int bCheckShift = false, int bCheckCtrl = false, int bCheckMenu = false)
	{
		//check the key itself
		int bButtonDown = m_mouse_button_buf[index];
		//check the shift modifier
		bButtonDown = bButtonDown && ( ! bCheckShift || m_mouse_button_shift[index]);
		//check the control modifier
		bButtonDown =  bButtonDown && ( ! bCheckCtrl || m_mouse_button_ctrl[index]);
		//check the menu  modifier
		bButtonDown = bButtonDown && ( ! bCheckMenu || m_mouse_button_menu[index]);
		
		return bButtonDown;
	}
	
	int IsMouseButtonUpDown(int index, int bClear = true)
	{
		int bIsMouseUpDown = m_mouse_button_up_down[index];
		if( bClear ) m_mouse_button_up_down[index] = false;
		return bIsMouseUpDown;
	}
	
	int IsMouseButtonDownUp(int index, int bClear = true)
	{
		int bIsMouseDownUp = m_mouse_button_down_up[index]
		if( bClear ) m_mouse_button_down_up[index] = false
		return bIsMouseDownUp;
	}
	
	int MouseX()
	{
		return m_mouse_x;
	}

	int MouseY()
	{
		return m_mouse_y;
	}

	float MouseZ()
	{
		return m_mouse_z;
	}

	FlushMouse()
	{
		m_mouse_button_cnt		= new int[3];
		m_mouse_button_buf		= new int[3];
		m_mouse_button_buf_old	= new int[3];
		m_mouse_button_up_down	= new int[3];
		m_mouse_button_down_up	= new int[3];
		m_mouse_button_shift		= new int[3];
		m_mouse_button_ctrl		= new int[3];
		m_mouse_button_menu		= new int[3];
	}

	// -------------------------------------------
	//|            JoyStick Functions             |
	// -------------------------------------------
	

};*/

/*
To receive events like mouse and keyboard input, or GUI events like "the OK
button has been clicked", we need an object which is derived from the
irr::IEventReceiver object. There is only one method to override:
irr::IEventReceiver::OnEvent(). This method will be called by the engine once
when an event happens. What we really want to know is whether a key is being
held down, and so we will remember the current state of each key.
*/
class MyEventReceiver : public IEventReceiver
{
public:
	// This is the one method that we have to implement
	virtual bool OnEvent(const SEvent& event)
	{
		// Remember whether each key is down or up
		if (event.EventType == irr::EET_KEY_INPUT_EVENT)
			KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

		return false;
	}

	// This is used to check whether a key is being held down
	virtual bool IsKeyDown(EKEY_CODE keyCode) const
	{
		return KeyIsDown[keyCode];
	}
	
	MyEventReceiver()
	{
		for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
			KeyIsDown[i] = false;
	}

private:
	// We use this array to store the current state of each key
	bool KeyIsDown[KEY_KEY_CODES_COUNT];
};
//VOIP Chat
class arrr
{
public:
private:
};

/** Example 004 Movement

This Tutorial shows how to move and animate SceneNodes. The
basic concept of SceneNodeAnimators is shown as well as manual
movement of nodes using the keyboard.  We'll demonstrate framerate
independent movement, which means moving by an amount dependent
on the duration of the last run of the Irrlicht loop.

Example 19.MouseAndJoystick shows how to handle those kinds of input.

As always, I include the header files, use the irr namespace,
and tell the linker to link with the .lib file.

The event receiver for keeping the pressed keys is ready, the actual responses
will be made inside the render loop, right before drawing the scene. So lets
just create an irr::IrrlichtDevice and the scene node we want to move. We also
create some other additional scene nodes, to show that there are also some
different possibilities to move and animate scene nodes.
*/